using Beaker.OpenCube.Render.Maths;
using Beaker.OpenCube.Render.Tracing;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace Beaker.OpenCube.Render.Cameras
{
	public abstract class Camera
		: ICamera
	{
		private readonly Point3 _position;
		private readonly Point3 _lookAt;

		private readonly Vector3 _up;
		private readonly Vector3 _u;
		private readonly Vector3 _v;
		private readonly Vector3 _w;

		protected Camera( Point3 position, Point3 lookAt, Vector3 up )
		{
			_position = position;
			_lookAt = lookAt;

			_up = up;
			_w = ( position - lookAt ).Normalize();
			_u = ( up ^ _w ).Normalize();
			_v = _w ^ _u;
		}

		[Pure]
		public Point3 Position
		{
			
			get { return _position; }
		}

		[Pure]
		public Point3 LookAt
		{
			
			get { return _lookAt; }
		}

		[Pure]
		public Vector3 U
		{
			
			get { return _u; }
		}

		[Pure]
		public Vector3 V
		{
			
			get { return _v; }
		}

		[Pure]
		public Vector3 W
		{
			
			get { return _w; }
		}

		public IObservable<IRenderUpdate> Render( Scene scene, ViewPlane viewPlane, ITracer tracer )
		{
			return RenderCore( scene, viewPlane, tracer );
		}

		protected abstract IObservable<IRenderUpdate> RenderCore( Scene scene, ViewPlane viewPlane, ITracer tracer );
	}

}